package part1to3.interpreter;

import token.*;

public class Interpreter {
    private final String text;
    private int pos;
    private Token currentToken;
    private Character currentChar;

    public Interpreter(String text){
        this.text = text;
        this.pos = 0;
        this.currentToken = null;
        this.currentChar = text.charAt(pos);
    }

    private void error() throws Exception {
        throw new Exception("Error parsing input");
    }

    private void advance(){
        pos++;
        if (pos>text.length()-1){
            this.currentChar = null;
        }
        else {
            this.currentChar = text.charAt(pos);
        }
    }

    private void skipWhitespace(){
        while (this.currentChar!=null && this.currentChar==' '){
            this.advance();
        }
    }

    private int integer(){
        StringBuilder sb = new StringBuilder();
        while (currentChar!=null && Character.isDigit(currentChar)){
            sb.append(currentChar);
            this.advance();
        }
        return Integer.parseInt(sb.toString());
    }

    private Token getNextToken() throws Exception {
        while (currentChar != null){
            if (this.currentChar == ' '){
                this.skipWhitespace();
                continue;
            }
            if (Character.isDigit(currentChar)){
                return new TK_Integer(this.integer());
            }
            if (currentChar=='+'){
                this.advance();
                return new TK_Plus();
            }
            if (currentChar=='-'){
                this.advance();
                return new TK_Minus();
            }
            this.error();
        }
        return new TK_EOF();
    }

    private void eat(Token.TokenType tokenType) throws Exception {
        if (currentToken.type == tokenType){
            currentToken = getNextToken();
        }
        else {
            this.error();
        }
    }

    public int term() throws Exception {
        Token token = currentToken;
        this.eat(Token.TokenType.INTEGER);
        return (Integer) token.value;
    }

    public int expr() throws Exception {
        currentToken = getNextToken();

        int result = this.term();
        while (currentToken.type == Token.TokenType.PLUS || currentToken.type== Token.TokenType.MINUS){
            Token token = currentToken;
            if (token.type== Token.TokenType.PLUS){
                eat(Token.TokenType.PLUS);
                result+=term();
            }
            else{
                eat(Token.TokenType.MINUS);
                result-=term();
            }
        }
        return result;
    }
}
